﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace Plugins.Engine
{
    /// <summary>
    /// This class is an implementation detail of the Mediator class.
    /// This will store all actions to be invoked
    /// </summary>
    [Serializable]
    public sealed class PluginDelegateMediator
    {
        readonly Dictionary<string, List<PluginWeakReference>> _actionMap = new Dictionary<string, List<PluginWeakReference>>();

        public void Add<T>(object target, string key, T item)
        {
            lock (_actionMap)
            {
                Delegate action = item as Delegate;
                if (action == null)
                {
                    throw new ArgumentException("Cannot process non-delegate target.");
                }
                if (!_actionMap.ContainsKey(key))
                {
                    _actionMap[key] = new List<PluginWeakReference>();
                }
                List<PluginWeakReference> weakActions = _actionMap[key];
                for (int i = weakActions.Count - 1; i > -1; --i)
                {
                    PluginWeakReference weakAction = weakActions[i];
                    if (weakAction.Contains(target, action.Method, typeof(T)))
                    {
                        throw new ArgumentException("Cannot register method.");
                    }
                }
                _actionMap[key].Add(new PluginWeakReference<T>(target, action.Method));
            }
        }

        public void Remove<T>(object target, string key, T item)
        {
            lock (_actionMap)
            {
                Delegate action = item as Delegate;
                if (action == null)
                {
                    throw new ArgumentException("Cannot process non-delegate target.");
                }
                if (!_actionMap.ContainsKey(key))
                {
                    return;
                }
                List<PluginWeakReference> weakActions = _actionMap[key];
                for (int i = weakActions.Count - 1; i > -1; --i)
                {
                    PluginWeakReference weakAction = weakActions[i];
                    if (weakAction.Contains(target, action.Method, typeof(T)))
                    {
                        weakActions.RemoveAt(i);
                    }
                }
                if (weakActions.Count == 0)
                    _actionMap.Remove(key);
            }
        }

        public void InvokeAction<T>(string action, Action<T> actionInvoker)
        {
            lock (_actionMap)
            {
                if (_actionMap.ContainsKey(action))
                {
                    foreach (PluginWeakReference weakReference in _actionMap[action])
                    {
                        weakReference.DynamicInvoke(actionInvoker, typeof(T));
                    }
                }
            }
        }
    }
}
